package com.mentalhealthplatform.global.log.manager;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.mentalhealthplatform.exception.ErrorResponse;
import com.mentalhealthplatform.exception.GlobalExceptionHandler;
import com.mentalhealthplatform.exception.user.UserNotFoundException;
import com.mentalhealthplatform.global.log.enums.LogStatus;
import com.mentalhealthplatform.global.rbac.model.CustomUserDetails;
import com.mentalhealthplatform.global.rbac.model.User;
import com.mentalhealthplatform.global.rbac.service.entity.BaseUserService;
import com.mentalhealthplatform.global.log.enums.OperationStatus;
import jakarta.servlet.http.HttpServletRequest;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.UUID;

@Aspect
@Component
public class ManagerLogAspect {

    private static final Logger logger = LoggerFactory.getLogger(ManagerLogAspect.class);

    @Autowired
    private HttpServletRequest request;

    @Autowired
    private BaseUserService baseUserService;

    @Autowired
    private ObjectMapper objectMapper;

    @Autowired
    private ManagerLogRepository managerLogRepository;

    @Autowired
    private GlobalExceptionHandler globalExceptionHandler;



    @Pointcut("@annotation(com.mentalhealthplatform.global.log.manager.ManagerLogAction)")
    public void managerLogPointcut() { }

    @Around("managerLogPointcut()")
    public Object logManagerOperation(ProceedingJoinPoint joinPoint) throws Throwable {
        long startTime = System.currentTimeMillis();

        // 初始化日志对象
        ManagerLog managerLog = new ManagerLog();
        managerLog.setOperationTime(LocalDateTime.now());
        managerLog.setOperationAddress(request.getRemoteAddr());
        managerLog.setHttpMethod(request.getMethod());

        // 获取方法签名和注解信息
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        ManagerLogAction logAction = signature.getMethod().getAnnotation(ManagerLogAction.class);

        managerLog.setSystemModule(logAction.module());
        managerLog.setOperationType(logAction.operationType());
        managerLog.setMethodName(getDetailedMethodName(joinPoint));

        // 获取请求 URL
        managerLog.setRequestUrl(request.getRequestURI());

        // 获取操作者对象
        User operator = getCurrentOperator();
        if (operator != null) {
            managerLog.setOperator(operator);
        } else {
            logger.warn("无法获取当前操作者，记录为空");
            managerLog.setOperator(null);
        }

        // 获取请求参数
        Object[] args = joinPoint.getArgs();
        managerLog.setRequestParams(serializeArgs(args));

        try {
            // 执行目标方法并捕获返回值
            Object result = joinPoint.proceed();

            // 操作成功
            managerLog.setOperationStatus(OperationStatus.SUCCESS);
            managerLog.setResponseParams(result != null ? result.toString() : "N/A");
            managerLog.setLogStatus(LogStatus.COMPLETED);

            return result;

        } catch (Throwable throwable) {
            // 操作失败，调用全局异常处理
            managerLog.setOperationStatus(OperationStatus.FAILURE);
            managerLog.setResponseParams(simplifyThrowableMessage(throwable));
            managerLog.setLogStatus(LogStatus.ERROR);

            // 调用全局异常处理器，处理异常
            return handleOperationException(throwable, managerLog);
        } finally {
            // 记录耗时
            long elapsedTime = System.currentTimeMillis() - startTime;
            managerLog.setElapsedTime(elapsedTime);

            // 保存日志
            managerLogRepository.save(managerLog);
        }
    }

    // 异常处理逻辑，简化并集成全局异常处理流程
    private Object handleOperationException(Throwable throwable, ManagerLog managerLog) {
        // 使用 GlobalExceptionHandler 进行统一的异常处理
        logger.warn(String.valueOf(throwable));
        ResponseEntity<ErrorResponse> responseEntity = globalExceptionHandler.processException(throwable);

        // 从 ResponseEntity 中获取 ErrorResponse
        ErrorResponse errorResponse = responseEntity.getBody();

        // 记录异常信息
        if (errorResponse != null) {
            managerLog.setResponseParams(errorResponse.getMessage());
            managerLog.setLogStatus(LogStatus.ERROR);
            managerLog.setOperationStatus(OperationStatus.FAILURE);
            managerLogRepository.save(managerLog);
        }

        // 返回统一的错误响应
        return responseEntity;
    }


    // 辅助方法：序列化参数为 JSON
    private String serializeArgs(Object[] args) {
        try {
            return objectMapper.writeValueAsString(args);
        } catch (Exception e) {
            logger.warn("参数序列化失败: {}", e.getMessage());
            return "参数序列化失败";
        }
    }

    // 获取方法的详细签名，包括类名和参数类型
    private String getDetailedMethodName(ProceedingJoinPoint joinPoint) {
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        String className = methodSignature.getDeclaringTypeName();
        String methodName = methodSignature.getName();

        return String.format("%s.%s()", className, methodName);
    }

    // 获取当前操作者对象
    private User getCurrentOperator() {
        try {
            // 从 Spring Security 上下文中获取 Authentication 对象
            Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
            if (authentication != null && authentication.isAuthenticated()) {
                Object principal = authentication.getPrincipal();
                if (principal instanceof CustomUserDetails) {
                    UUID userId = ((CustomUserDetails) principal).getId();
                    return baseUserService.findById(userId);
                } else if (principal instanceof String) {
                    return mapUsernameToOperator((String) principal);
                }
            }
        } catch (Exception e) {
            logger.warn("无法获取当前操作者: {}", e.getMessage(), e);
        }
        return null;
    }

    // 映射用户名到 User 的逻辑
    private User mapUsernameToOperator(String username) {
        try {
            return baseUserService.findByUsername(username)
                    .orElseThrow(() -> new UserNotFoundException("用户名不存在: " + username));
        } catch (UserNotFoundException e) {
            logger.warn("无法找到用户名 {} 对应的用户: {}", username, e.getMessage());
            return null;
        }
    }

    // 简化 Throwable 的信息
    private String simplifyThrowableMessage(Throwable throwable) {
        String message = throwable.getMessage();

        // 如果异常信息太长，截取一部分
        if (message != null && message.length() > 200) {
            message = message.substring(0, 200) + "...";
        }

        // 如果是数据库异常，且存在堆栈信息
        if (throwable instanceof DataAccessException) {
            message = "数据库操作失败: " + (message != null ? message : "未知错误");
        } else if (throwable instanceof BadCredentialsException) {
            message = "认证失败: " + (message != null ? message : "用户名或密码错误");
        } else {
            message = throwable.getClass().getSimpleName() + ": " + (message != null ? message : "未知错误");
        }

        return message;
    }
}
